Quentin Mille
Simon Côte
Julien Grenet
Hassan Ayoubi
Raphaël Linard
Raphaël Haustant
L’agence AIL3C (Agence indépendante de lutte contre la cybercriminalité) a réussi à localiser une base d’opération de cybercriminels dangereux. Lors d’une
opération d’infiltration menée par l’agent K57, il réussit à capturer des informations sensibles dans la salle des serveurs. Malheureusement, il se retrouve
à devoir se cacher dans une pièce équipée de micros et de murs empêchant toute communication extérieure. Il finit par être capturé.
Objectif : Nous devons concevoir et soumettre à l’équipe R&D une solution permettant la communication sans être repéré.
Ayant désormais la vision complète de la chaîne de transmission pour réaliser la communication, vous devez mettre en place un prototype pour faire la démonstration de la viabilité de votre solution.
On a la partie verte pour la phase d’emission / de transmission et la partie bleue pour la partie.

Explication détaillé de la chaine de transmission:
1. Message
L’agent réfléchit à un message simple et consit pour être le plus discret possible
2. PAD
L’agent écrit à l’aide du pavé numérique du pad et envoie le message. Ce message est converti en binaire.
3. Encodage Manchester
Le message binaire est encodé en Manchester.
Un 0 se transforme en 01 et un 1 se transforme en 10.
Le codage Manchester présente de nombreux avantages :
4. Modulation ASK / FSK

5. Fichier audio
La modulation FSK / ASK donne un fichier audio qui est ensuite émit par les hauts parleurs du pad sous forme d’un signal ultrason, non audible pour l’être humain mais transmissible et récupérable
6. Microphone
Le microphone capte l’audio. Il le transfert en signal analogique électrique
7.Récepteur
On suppose que la réception du signal se fait directement dans le réseau de la base
7. Démodulation ASK / FSK
Le fichier audio est démodulé pour obtenir des bits.
8. Décodage Manchester inversé
Les bits sont décodés en Manchester pour retouver leur bits d’origine.
9. Fichier audio / Message
On peut lire le fichier audio ou juste convertir ce signal suite binaire en ASCII pour lire le message
10.Exemple d’un message
Exemple avec la lettre H :

7. Mirco : Ce signal est transmit par les hauts - parleurs du pad vers le micro
8. Recepteur (Antenne) : L’antenne récupère ce signal
9. Démodulation : La démodulation donne donc : 01 10 01 01 10 01 01 01
10. Décodage : En décodant on obtient : 0100 1000
11. Binaire converti en message (ASCII) : 0100 1000 donne donc 72 en décimal soit la lettre “H”
12. Réception (Agent extérieur) : L’agent reçoit la lettre “H”
Pour notre code on optera pour une structure dans laquelle on définit toutes les fonctions nécessaires et ensuite on exécutera le code final de notre POC en utilisant ces fonctions.
# Importation des bibliothèques nécessaires
import numpy as np # Import de la bibliothèque numpy
import matplotlib.pyplot as plt # Import de la bibliothèque matplotlib
from scipy.signal import periodogram # Import de la fonction periodogram du module signal de scipy
# 1. Conversion du texte en binaire (en une liste de bits)
def texte_vers_binaire(message_1):
# '08b' -> convertit en chaine de 8 bits
# ord(char) -> convertit chaque caratère en ASCII
message_binaire_1 = [int(bit) for char in message_1 for bit in format(ord(char), '08b')]
return message_binaire_1
# 2. Encodage Manchester (prend une liste de bits et retourne une liste de bits encodés)
# Un bit '0' -> '01'
# Un bit '1' -> '10'
def encodage_manchester(message_binaire_1):
encodage_M = []
for bit in message_binaire_1:
if bit == 1:
encodage_M.extend([1, 0]) # Manchester pour 1
else:
encodage_M.extend([0, 1]) # Manchester pour 0
return encodage_M
# Initialisation des variables
Fe = 52000 # Fréquence d'échantillonnage
baud = 300 # Baud
Ap = 1 # Amplitude porteuse
Fp = 2000 # Fréquence porteuse
Fp1 = 2000 # Fréquence porteuse 1
Fp2 = 5000 # Fréquence porteuse 2
Ns = int(Fe / baud) # Nombre de symboles par bit
# 3. Modulation ASK
def modulation_ASK(encodage_M):
# Initialisation des variables
# Génére un message qui duplique chaque bit du message encodé Ns fois pour synchroniser le signal binaire avec la porteuse
M_duplique = np.repeat([int(bit) for bit in encodage_M], Ns)
N = len(M_duplique) # Taille de M_duplique
D = N / Fe # Durée
t = np.arange(0, D, 1 / Fe) # Vecteur temps
# Générer la porteuse ASK
Porteuse = Ap * np.sin(2 * np.pi * Fp * t)
# Signal ASK
ASK = M_duplique * Porteuse
return t, M_duplique, Porteuse, ASK
# 1. Démodulation ASK
def demodulation_ASK(t, ASK, encodage_M):
# Génére un message qui duplique chaque bit du message encodé Ns fois pour synchroniser le signal binaire avec la porteuse
M_duplique = np.repeat([int(bit) for bit in encodage_M], Ns)
N = len(M_duplique) # Taille de M_duplique
# Recréer la porteuse
Porteuse = np.sin(2 * np.pi * Fp * t)
# Produit entre le signal modulé ASK et la porteuse
Produit = ASK * Porteuse
# Intégration sur chaque période de symbole (avec la méthode des Trapèzes)
Res= [] # Résultat de l'intégration
i=0
for i in range(0,N,Ns):
Res.append (np.trapz(Produit[i:i+Ns],t[i:i+Ns]))
# Si Res > 0 donc on a reçu un 1 (True) sinon un 0 (False)
message_demodule = np.array(Res) > 0 # Renvoie True (si > 0) ou False sinon
# Decodage du signal démodulé
message_demodule_ASK = [] # Résultat du comparateur
for ii in range (0,len(message_demodule)):
if message_demodule [ii] == True:
message_demodule_ASK.extend([int(1)]) # Si l'intégrale est positive, c'est un 1
else:
message_demodule_ASK.extend([int(0)]) # Si l'intégrale est négative ou nulle, c'est un 0
return message_demodule_ASK
# 2. Décodage Manchester inversé
def decodage_manchester(message_binaire_2):
# Décodage Manchester (prend une liste de bits encodés et retourne une liste de bits)
# Reconstruction du message binaire original
binaire_texte = []
for i in range(0, len(message_binaire_2), 2):
if message_binaire_2[i:i+2] == [1, 0]: # Bloc "10" correspond à 1
binaire_texte.append(1)
elif message_binaire_2[i:i+2] == [0, 1]: # Bloc "01" correspond à 0
binaire_texte.append(0)
return binaire_texte
# 3. Binaire vers message final
def binaire_vers_texte(binaire_texte):
# Conversion d'une liste de bits en texte (chaîne de caractères)
texte = ''
for i in range(0, len(binaire_texte), 8):
# Convertit chaque groupe de 8 bits en caractère ASCII
byte = binaire_texte[i:i+8]
texte += chr(int(''.join(map(str, byte)), 2)) # Conversion des bits en nombre entier puis en caractère
return texte
## 5. Détection d'erreurs
def detection_erreur(encodage, message_demodule):
Erreur = [] # Initialiser une liste pour stocker les erreurs
for i in range(len(encodage)):
if encodage[i] != message_demodule[i]:
Erreur.append(1) # Erreur détectée
else:
Erreur.append(0) # Pas d'erreur
# Compter le nombre d'erreurs
nombre_erreurs = sum(Erreur)
print("Erreur de réception :\n", Erreur)
print(f"Nombre d'erreurs : {nombre_erreurs}")
return Erreur
# Exécution du code
print("Message original :", texte_entree)
message_binaire_1 = texte_vers_binaire(texte_entree)
print("Message en binaire :", message_binaire_1)
message_encode = encodage_manchester(message_binaire_1)
print("Messag encodé en Manchester :", message_encode)
###------- Modulation ASK ----------###
t, M_duplique, Porteuse, ASK = modulation_ASK(message_encode)
# Affichage des graphiques
plt.figure(figsize=(10, 8))
plt.subplot(3, 1, 1)
plt.plot(t, M_duplique, drawstyle='steps-post')
plt.title('Message Encodé en Manchester')
plt.xlabel('Temps (s)')
plt.ylabel('Amplitude')
plt.grid()
plt.subplot(3, 1, 2)
plt.xlim (0,0.01)
plt.plot(t, Porteuse)
plt.title('Porteuse P(t)')
plt.xlabel('Temps (s)')
plt.ylabel('Amplitude')
plt.grid()
plt.subplot(3, 1, 3)
plt.xlim (0,0.1)
plt.plot(t, ASK)
plt.title('Signal Modulé ASK(t)')
plt.xlabel('Temps (s)')
plt.ylabel('Amplitude')
plt.grid()
plt.tight_layout()
plt.show()
###------- Modulation FSK ----------###
t, M_duplique, P1, P2, FSK = modulation_FSK(message_encode)
# Affichage des graphiques
plt.figure(figsize=(10, 8))
plt.subplot(3, 1, 1)
plt.plot(t, M_duplique, drawstyle='steps-post')
plt.title('Message Encodé en Manchester')
plt.xlabel('Temps (s)')
plt.ylabel('Amplitude')
plt.grid()
plt.subplot(3, 1, 2)
plt.xlim (0,0.01)
plt.plot(t, P1)
plt.title('Porteuse P(t)')
plt.xlabel('Temps (s)')
plt.ylabel('Amplitude')
plt.grid()
plt.subplot(3, 1, 2)
plt.xlim (0,0.01)
plt.plot(t, P2)
plt.title('Porteuse P(t)')
plt.xlabel('Temps (s)')
plt.ylabel('Amplitude')
plt.grid()
plt.subplot(3, 1, 3)
plt.xlim (0,0.1)
plt.plot(t, FSK)
plt.title('Signal Modulé ASK(t)')
plt.xlabel('Temps (s)')
plt.ylabel('Amplitude')
plt.grid()
plt.tight_layout()
plt.show()
# Démodulation FSK
message_demodule = demodulation_FSK(t, FSK)
print("Message démodulé en codage manchester : ",message_demodule)
Erreur = detection_erreur(message_encode, message_demodule)
# Démodulation ASK
message_demodule1 = demodulation_ASK(t, ASK)
print("Message démodulé en codage manchester : ",message_demodule1)
Erreur1 = detection_erreur(message_encode, message_demodule1)
# Décodage FSK
message_decode = decodage_manchester(message_demodule)
print("Message décodé en binaire :", message_decode)
message_final = binaire_vers_texte(message_decode)
print("Message final décodé :", message_final)
# Décodage ASK
message_decode1 = decodage_manchester(message_demodule1)
print("Message décodé en binaire :", message_decode)
message_final1 = binaire_vers_texte(message_decode1)
print("Message final décodé :", message_final1)
from scipy.io.wavfile import write
import sounddevice as sd
from scipy.signal import periodogram
# Fonction pour sauvegarder le signal audio
def save_audio_signal(signal, filename, sample_rate):
signal_np = np.array(signal) # Convertir en tableau NumPy
write(filename, sample_rate, signal_np.astype(np.float32))
# Fonction pour jouer un signal audio
def play_audio_signal(signal, sample_rate):
signal_np = np.array(signal) # Convertir en tableau NumPy
sd.play(signal_np, sample_rate)
sd.wait()
# Filtre Passe Haut
f1 = 2000 # fréquence du signal S1
f2 = 5000
f3= 10000
f4 = 26000 # fréquence du signal S2
f5 = 25000
f6 = 20000
# S1 et S2 et S=S1+S2
S1 = Ap*np.sin(2*np.pi*f1*t) # création d'une sinusoïde de fréquence f1
S2 = Ap*np.sin(2*np.pi*f2*t) # création d'une sinusoïde de fréquence f2
S3 = Ap*np.sin(2*np.pi*f3*t)
S4 = Ap*np.sin(2*np.pi*f4*t)
S5 = Ap*np.sin(2*np.pi*f5*t)
S6 = Ap*np.sin(2*np.pi*f6*t)
S = S1 + S2 + S3 + S4 + S5 + S6
# calcul de la transformée de Fourier avec la fonction periodogram
f,FFT = periodogram(S,Fe) # f: vecteur des fréquences et FFT:la transformée de Fourier du signal S=S1+S2
# Affichage du signal------------------------------------------------
plt.plot(t,S) # affichage via la fonction plot de Matplotlib
plt.xlabel('Temps (s)') # définition de l'axe des abscisses
plt.ylabel('Amplitude') # définition de l'axe des ordonnées
plt.title ('Signal S',fontsize=14)
plt.grid()
plt.show() # affichage des courbes
# Affichage du de la transformée de Fourier FFT du signal S=S1+S2-----------------
plt.plot(f,FFT) # affichage via la fonction plot de Matplotlib
plt.xlabel('Fréquence (Hz)') # définition de l'axe des abscisses
plt.ylabel('Module') # définition de l'axe des ordonnées
plt.xlim(0, 28000)
plt.grid()
plt.title ('Module de la Transformée de Fourier du signal S=S1+S2',fontsize=14)
plt.show()
# définir la fréquence de coupure fc du filtre à 75 Hz
fc = 25000
# on définit une variable qui reçoit le signal filtré de la même taille que la transformée de Fourier (FFT)
FFT_filtre = FFT
# on réalise un filre passe haut comme suit :
for i in range(len(f)):
if f[i] < fc: # on coupe toutes les fréquences < 75 Hz
FFT_filtre[i] = 0.0
print(f)
# on calcule la transfomrée de Fourier inverse du signal après filtrage en utilsant la fonction ifft de Python
# la FFT inverse permet de revenir dans l'espace temporal (espace fréquentiel -> espace temps)
FFT_inverse = np.fft.ifft(FFT_filtre)
# attention le résulat est un nombre complexe
# on ne doit donc représenter que la partie réelle, imaginaire ou le module (réél^2 + imag^2)
plt.plot(f,FFT_filtre) # affichage via la fonction plot de Matplotlib
plt.xlabel('Fréquence (Hz)') # définition de l'axe des abscisses
plt.ylabel('Module') # définition de l'axe des ordonnées
plt.xlim(0, 28000)
plt.grid()
plt.title ('Module de la Transformée de Fourier du signal filtré s(t)',fontsize=14)
plt.show()
plt.plot(np.real(FFT_inverse)) # affichage via la fonction plot de Matplotlib de la partie réelle
plt.ylabel('Amplitude') # définition de l'axe des ordonnées
plt.xlim(0, 200)
plt.grid()
plt.title ('Le signal obtenu après filtrage',fontsize=14)
plt.show()